"""
体重记录 DAO 层
负责体重数据的数据库访问操作（增删改查）
"""
from datetime import datetime
from typing import Optional

from app.db import db
from app.Models.HealthModels.WeightModels.WeightModel import Weight  # 导入你的 Weight 模型


class WeightDAO:
    @staticmethod
    def add_weight(user_id: int, weight: float, submit_time: datetime = None) -> Weight:
        """
        新增体重记录
        :param user_id: 用户ID（外键关联user_info表）
        :param weight: 体重（kg）
        :param submit_time: 提交时间（默认当前时间）
        :return: 新增的Weight模型实例
        :raises: 数据库操作异常
        """
        try:
            # 若未指定提交时间，默认使用当前时间
            submit_time = submit_time or datetime.now()

            # 创建体重记录实例
            new_weight = Weight(
                user_id=user_id,
                weight=weight,
                submit_time=submit_time
            )

            # 提交到数据库
            db.session.add(new_weight)
            db.session.commit()
            return new_weight
        except Exception as e:
            # 回滚事务
            db.session.rollback()
            raise RuntimeError(f"新增体重记录失败：{str(e)}") from e

    @staticmethod
    def get_weight_by_id(weight_id: int) -> Optional[Weight]:
        """
        根据ID查询体重记录
        :param weight_id: 体重记录ID（主键）
        :return: 找到的Weight实例，未找到返回None
        """
        try:
            return Weight.query.get(weight_id)
        except Exception as e:
            raise RuntimeError(f"查询体重记录（ID:{weight_id}）失败：{str(e)}") from e

    @staticmethod
    def get_weights_by_user(
            user_id: int,
            start_date: datetime = None,
            end_date: datetime = None,
            page: int = 1,
            per_page: int = 20
    ) -> tuple[list[Weight], int]:
        """
        根据用户ID查询体重记录（支持时间范围过滤和分页）
        :param user_id: 用户ID
        :param start_date: 开始时间（可选，查询该时间之后的记录）
        :param end_date: 结束时间（可选，查询该时间之前的记录）
        :param page: 页码（默认第1页）
        :param per_page: 每页条数（默认20条）
        :return: (体重记录列表, 总记录数)
        """
        try:
            # 基础查询：按用户ID过滤
            query = Weight.query.filter_by(user_id=user_id)

            # 时间范围过滤
            if start_date:
                query = query.filter(Weight.submit_time >= start_date)
            if end_date:
                query = query.filter(Weight.submit_time <= end_date)

            # 按提交时间降序排序（最新的在前）
            query = query.order_by(Weight.submit_time.desc())

            # 分页查询
            pagination = query.paginate(page=page, per_page=per_page, error_out=False)
            return pagination.items, pagination.total
        except Exception as e:
            raise RuntimeError(f"查询用户（ID:{user_id}）体重记录失败：{str(e)}") from e

    @staticmethod
    def get_latest_weight(user_id: int) -> Optional[Weight]:
        """
        查询用户最新的一条体重记录
        :param user_id: 用户ID
        :return: 最新的Weight实例，无记录返回None
        """
        try:
            return Weight.query.filter_by(user_id=user_id).order_by(Weight.submit_time.desc()).first()
        except Exception as e:
            raise RuntimeError(f"查询用户（ID:{user_id}）最新体重记录失败：{str(e)}") from e

    @staticmethod
    def update_weight(
            weight_id: int,
            new_weight: float = None,
            new_submit_time: datetime = None
    ) -> Optional[Weight]:
        """
        更新体重记录（支持部分字段更新）
        :param weight_id: 要更新的体重记录ID
        :param new_weight: 新体重（可选，不填则不更新）
        :param new_submit_time: 新提交时间（可选，不填则不更新）
        :return: 更新后的Weight实例，未找到返回None
        :raises: 数据库操作异常
        """
        try:
            # 查找要更新的记录
            weight = Weight.query.get(weight_id)
            if not weight:
                return None

            # 部分字段更新（只更新传入的非None参数）
            if new_weight is not None:
                weight.weight = new_weight
            if new_submit_time is not None:
                weight.submit_time = new_submit_time

            # 提交事务
            db.session.commit()
            return weight
        except Exception as e:
            db.session.rollback()
            raise RuntimeError(f"更新体重记录（ID:{weight_id}）失败：{str(e)}") from e

    @staticmethod
    def delete_weight(weight_id: int) -> bool:
        """
        删除体重记录
        :param weight_id: 要删除的体重记录ID
        :return: 删除成功返回True，未找到返回False
        :raises: 数据库操作异常
        """
        try:
            weight = Weight.query.get(weight_id)
            if not weight:
                return False

            db.session.delete(weight)
            db.session.commit()
            return True
        except Exception as e:
            db.session.rollback()
            raise RuntimeError(f"删除体重记录（ID:{weight_id}）失败：{str(e)}") from e

    @staticmethod
    def delete_weights_by_user(user_id: int) -> int:
        """
        批量删除某个用户的所有体重记录（谨慎使用）
        :param user_id: 用户ID
        :return: 删除的记录条数
        :raises: 数据库操作异常
        """
        try:
            delete_count = Weight.query.filter_by(user_id=user_id).delete()
            db.session.commit()
            return delete_count
        except Exception as e:
            db.session.rollback()
            raise RuntimeError(f"批量删除用户（ID:{user_id}）体重记录失败：{str(e)}") from e
